package Spark高级特性.闭包

import org.apache.spark.rdd.RDD
import org.junit.Test

/**
 * 1.一个函数如果在另外一个方法或者函数或者类中去定义，这个函数内部依赖了外部类的某一个变量，这个函数就要持有外部类的对象，也就是持有(封闭)该类的作用域，此时这个函数被称为闭包
 * 2.在算子所传入的函数中，调用了外部的变量，该变量和所对应的类会随着Task被一起序列化，然后被分发到不同的Executor中去执行，外部所依赖的有多少个Task就会被复制对应的份数
 */
class closure {

  /**
   *  定义一个高阶函数，里面有一个变量,返回一个函数，通过该变量完成一个计算
   */
  @Test
  def test: Unit ={
    // 在调用 f 的时候，可以通过 f 访问到 closure() 作用域中的内容
    // 说明 f 携带了一个作用域
    // 如果一个函数携带了一个外包的作用域，这种函数我们称之为闭包
    /**
     *  闭包的本质就是一个函数
     *  在scala中函数是一个特殊的类型Function
     *  闭包也是一个特殊的Function类型的对象
     */
    val f:Int=>Double = closure()
    val area = f(5)
    println(area)
  }
  /**
   * 返回一个新的函数
   */
   def closure(): Int=>Double ={
     val m = 3.14
     val areaFunction = (r:Int) => math.pow(r,2)*m
     areaFunction
   }

}
class myClass{

  val  str = "hello"

  def doStuff(rdd:RDD[String]):RDD[String] ={
    rdd.map(item => str+item)  // 引用myClass的一个成员变量，说明可以访问myClass的作用于，该函数可以看成是一个闭包，封闭的是myClass的作用域
                               // 此时，在分发给不同的Executor时，由于封闭了myClass的作用域，所以会依赖于myClass，myClass和该函数都要一起被序列化，发到不同的节点中执行
                               //  * 若myClass不能被序列化，将会报错
                               //  * 若在此过程中依赖了一个很大的集合，那么这个集合会随着每一个Task分发，也可以理解为依赖外部的数据，都会被复制成很多份
  }

}